package com.aim.util;

import com.aim.util.extractors.DoubleValueExtractor;
import com.aim.util.extractors.NumberExtractor;
import com.aim.util.extractors.ValueExtractor;
import com.google.common.primitives.Doubles;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.math3.stat.StatUtils;
import org.apache.commons.math3.stat.descriptive.rank.Median;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * User: User
 * Date: 5/11/14
 * Time: 10:39 PM
 */
public class ListUtil {

    public static <P,T,V extends Number> double[] toDoubleArray(Collection<P> collection, ValueExtractor<P,V> adapter, NumberExtractor<T, V> valueExtractor){
        return null;
    }

    public static <T, V extends Number> double[] toDoubleArray(Collection<T> collection, ValueExtractor<T, V> valueExtractor){
        double[] values = new double[collection.size()];
        int index = 0;
        for (T t : collection) {
            values[index++] = valueExtractor.getValue(t).doubleValue();
        }
        return values;
    }

    public static <T, V extends Number> double mean(Collection<T> list, ValueExtractor<T, V> valueExtractor){
        double[] doubles = toDoubleArray(list, valueExtractor);
        return StatUtils.mean(doubles);
    }

    public static <T extends Number> double sum(Collection<T> numbers){
      double[] numbersArray = Doubles.toArray(numbers);
      return StatUtils.sum(numbersArray);
    }




    public static <T, V extends Number> double variance(Collection<T> list, ValueExtractor<T, V> valueExtractor){
        double[] doubles = toDoubleArray(list, valueExtractor);
        return StatUtils.variance(doubles);
    }

    public static <T, V extends Number> MeanVarPair meanAndVariance(Collection<T> list, ValueExtractor<T, V> valueExtractor){
        double[] doubles = toDoubleArray(list, valueExtractor);
        double mean = StatUtils.mean(doubles);
        double variance = StatUtils.variance(doubles, mean);
        return new MeanVarPair(mean, variance);
    }

    public static  double mean(Collection<? extends Number> list){
        double[] doubles = Doubles.toArray(list);
        return StatUtils.mean(doubles);
    }

    public static  double variance(Collection<? extends Number> list){
        double[] doubles = Doubles.toArray(list);
        return StatUtils.variance(doubles);
    }

    public static MeanVarPair meanAndVariance(Collection<? extends Number> list){
        double[] doubles = Doubles.toArray(list);
        double mean = StatUtils.mean(doubles);
        double variance = StatUtils.variance(doubles, mean);
        return new MeanVarPair(mean, variance);
    }

    public static double median(Collection<? extends Number> list){
        double[] doubles = Doubles.toArray(list);
        Median median = new Median();
        return median.evaluate(doubles);
    }

    public static <N extends Number> MinMax<N> minMax(List<N> list){
        if (list == null || list.size() == 0){
            return new MinMax<N>(null, null);
        }
        N min = list.get(0);
        N max = list.get(0);
        double dMinVal = min.doubleValue();
        double dMaxValue = max.doubleValue();

        for (int i = 0; i < list.size(); i++) {
            N n = list.get(i);
            double dValue = n.doubleValue();
            if (dValue < dMinVal){
                dMinVal = dValue;
                min = n;
            } else if (dValue > dMaxValue) {
                dMaxValue = dValue;
                max = n;
            }
        }
        return new MinMax<N>(min, max);
    }

    public static <N extends Number> StatData<N> calcStatData(List<N> list){
        MeanVarPair meanVarPair = meanAndVariance(list);
        MinMax<N> minMax = minMax(list);
        return new StatData<N>(minMax.min(), minMax.max(), meanVarPair.mean(), meanVarPair.variance());
    }











}
